home *** CD-ROM | disk | FTP | other *** search
/ IRIS Performer 2.2 Friends Demo / SGI IRIS Performer 2.2 Friends Demo.iso / friends / medit / pfLoader / Internalstuff / filer.c < prev    next >
C/C++ Source or Header  |  1997-11-20  |  30KB  |  1,230 lines

  1. /************************************************************************
  2. Data creation/manipulation routines for the filer
  3. ************************************************************************/
  4.  
  5. /************************************************************************
  6. Alias some data types to ease transition from ModelWorks to libmw
  7. ************************************************************************/
  8. #ifdef POX
  9. #define MaxName mwMaxName
  10. #define FileError mwFileError
  11. #define FileErrorType mwErrorType
  12. #define FileHadNormals mwFileHadNormals
  13.  
  14. #define FreeTree mwFreeTree
  15. #define NewTreeBranch mwNewTreeBranch
  16. #define ScanTree mwScanTree
  17. #define AddPolygon mwAddPolygon
  18. #define FreePolygon mwFreePolygon
  19. #define CopyOfPolygon mwCopyOfPolygon
  20. #define CopyOfPolygonBead mwCopyOfPolygonBead
  21.  
  22.  
  23. #ifndef TX_NULL
  24. #define TX_NULL 0
  25. #endif
  26.  
  27. typedef mwFile            ModelFile;
  28. typedef mwFilePtr        ModelFilePtr;
  29.  
  30. typedef mwMaterial        Material;
  31. typedef mwMaterialPtr        MaterialPtr;
  32. typedef mwTexture        Texture;
  33. typedef mwTexturePtr        TexturePtr;
  34.  
  35. typedef mwObject        ModelObject;
  36. typedef mwObjectPtr        ModelObjectPtr;
  37. typedef mwTree            Tree;
  38. typedef mwTreePtr        TreePtr;
  39. typedef mwPolygon        Polygon;
  40. typedef mwPolygonPtr        PolygonPtr;
  41. typedef mwPolygonBead        PolygonBead;
  42. typedef mwPolygonBeadPtr    PolygonBeadPtr;
  43.  
  44. /* Hierarchy branches */
  45. #define GroupBranch mwGroupBranch
  46. #define PolygonBranch mwPolygonBranch
  47. #define LodBranch mwLodBranch
  48. #define InstanceBranch mwInstanceBranch
  49. #define SwitchBranch mwSwitchBranch
  50. #define DcsBranch mwDcsBranch
  51. #define VRMLBranch mwVRMLBranch
  52. #define SolidBranch mwSolidBranch
  53.  
  54. /* Engine branches */
  55. #define ActivatorEngine mwActivatorEngine
  56. #define DeactivatorEngine mwDeactivatorEngine
  57.  
  58. #define TimeEngine mwTimeEngine
  59. #define LineEngine mwLineEngine
  60. #define AngleEngine mwAngleEngine
  61. #define WaveEngine mwWaveEngine
  62. #define SensorEngine mwSensorEngine
  63.  
  64. #define ScalarEngine mwScalarEngine
  65. #define SplineEngine mwSplineEngine
  66. #define CompareEngine mwCompareEngine
  67. #define MatrixEngine mwMatrixEngine
  68.  
  69. #define SwitchOutput mwSwitchOutput
  70. #define DcsOutput mwDcsOutput
  71.  
  72. #else
  73.  
  74. #define MaxName meditMaxName
  75. #define FileError meditFileError
  76. #define FileErrorType meditErrorType
  77. #define FileHadNormals meditFileHadNormals
  78.  
  79. #ifndef TX_NULL
  80. #define TX_NULL 0
  81. #endif
  82.  
  83. #define mwFreeFile        meditFreeFile
  84. #define mwOriginalPath        meditOriginalPath
  85. #define FileHadNormals        meditFileHadNormals
  86. #define mwSeqCycle        meditSeqCycle
  87. #define mwSeqCycle        meditSeqCycle
  88. #define ReadModel        ReadMedit
  89. #define WriteModel        WriteMedit
  90. #define CurrentModelFile    CurrentMeditFile
  91. #define mwErrorList        meditErrorList
  92. #define NewModelFile        NewMeditFile
  93. #define AddObject        meditAddObject
  94. #define NewTreeBranch        meditNewTreeBranch
  95. #define mwAddTreeBranch        meditAddTreeBranch
  96. #define mwAddMaterial        meditAddMaterial
  97. #define mwAddTexture        meditAddTexture
  98. #define AddPolygon        meditAddPolygon
  99. #define mwAddPolygonBead    meditAddPolygonBead
  100. #define mwConvertTo_Y_is_up    meditConvertTo_Y_is_up
  101. #define mwConvertTo_Z_is_up    meditConvertTo_Z_is_up
  102.  
  103. typedef meditFile        ModelFile;
  104. typedef meditFilePtr        ModelFilePtr;
  105.  
  106. typedef meditMaterial        Material;
  107. typedef meditMaterialPtr    MaterialPtr;
  108. typedef meditTexture        Texture;
  109. typedef meditTexturePtr        TexturePtr;
  110.  
  111. typedef meditObject        ModelObject;
  112. typedef meditObjectPtr        ModelObjectPtr;
  113. typedef meditTree        Tree;
  114. typedef meditTreePtr        TreePtr;
  115. typedef meditPolygon        Polygon;
  116. typedef meditPolygonPtr        PolygonPtr;
  117. typedef meditPolygonBead    PolygonBead;
  118. typedef meditPolygonBeadPtr    PolygonBeadPtr;
  119.  
  120. /* Hierarchy branches */
  121. #define GroupBranch meditGroupBranch
  122. #define PolygonBranch meditPolygonBranch
  123. #define LodBranch meditLodBranch
  124. #define InstanceBranch meditInstanceBranch
  125. #define SwitchBranch meditSwitchBranch
  126. #define DcsBranch meditDcsBranch
  127. #define VRMLBranch meditVRMLBranch
  128. #define SolidBranch meditSolidBranch
  129.  
  130. /* Engine branches */
  131. #define ActivatorEngine meditActivatorEngine
  132. #define DeactivatorEngine meditDeactivatorEngine
  133.  
  134. #define TimeEngine meditTimeEngine
  135. #define LineEngine meditLineEngine
  136. #define AngleEngine meditAngleEngine
  137. #define WaveEngine meditWaveEngine
  138. #define SensorEngine meditSensorEngine
  139.  
  140. #define ScalarEngine meditScalarEngine
  141. #define SplineEngine meditSplineEngine
  142. #define CompareEngine meditCompareEngine
  143. #define MatrixEngine meditMatrixEngine
  144.  
  145. #define SwitchOutput meditSwitchOutput
  146. #define DcsOutput meditDcsOutput
  147.  
  148.  
  149. #endif
  150.  
  151. /************************************************************************
  152. Memory management
  153. ************************************************************************/
  154. #define Free free
  155. #define Allocate malloc
  156. #define Reallocate realloc
  157. #define CopyOfString strdup
  158.  
  159. /************************************************************************
  160. Some defines to make coding nicer
  161. ************************************************************************/
  162. #define LoopThroughAllObjects(o) for (o=CurrentModelFile->FirstObject; o; o=o->Next)
  163. #define LoopThroughAllTextures(t) for (t=CurrentModelFile->FirstTexture; t; t=t->Next)
  164. #define LoopThroughAllMaterials(m) for (m=CurrentModelFile->FirstMaterial; m; m=m->Next)
  165. #define LoopThroughBranchesPolygons(t, p) for (p=t->FirstPolygon; p; p=p->Next)
  166. #define LoopThroughPolygonsBeads(p, pb) for (pb=p->FirstBead; pb; pb=pb->Next)
  167.  
  168. /************************************************************************
  169. Global variables
  170. ************************************************************************/
  171. flag FileHadNormals;
  172. ModelFilePtr CurrentModelFile;
  173. char mwOriginalPath[MaxFileName];
  174.  
  175. static flag ReadingExternal;
  176. static ModelObjectPtr ExternalObject;
  177.  
  178. static flag MissingTextures;
  179. static flag CurrentSmoothing;
  180.  
  181. static char ProgName[] = "ModelWorks";
  182. static char FileExtension[] = ".medit";
  183. static char FilePath[MaxFileName], FileName[MaxFileName];
  184.  
  185. static flag OnlySaveUsed = FALSE;
  186. static ModelObjectPtr ObjectBeingSaved = NULL;
  187.  
  188. static void FreeExternalFile(reg ModelFilePtr f);
  189.  
  190. static MaterialPtr *CurrentMaterial(void)
  191. {
  192.     static MaterialPtr CurrentMat = NULL;
  193.     return &CurrentMat;
  194. }
  195. static MaterialPtr *FirstMaterial(void)
  196. {
  197.     return &(CurrentModelFile->FirstMaterial);
  198. }
  199.  
  200. #define DefaultColour 0xff808080
  201.  
  202. /************************************************************************
  203. Errors
  204. ************************************************************************/
  205. flag FileError;
  206. int FileErrorType;
  207. #define ifbad(x) if (!(x))
  208. #define GetStuff(x) ifbad(x) return
  209. enum {
  210. REACHED_END=0,            /* Types of error */
  211. UNKNOWN_FILE,
  212. BAD_FILE,
  213. FILE_NOT_FOUND,
  214. TOO_MANY_REALS,
  215.  
  216. BAD_STRING,
  217. BAD_REVISION,
  218. BAD_MATERIAL_INDEX,
  219. BAD_MATERIAL,
  220. BAD_VERTEX,
  221.  
  222. BAD_VERTEX_INDEX,
  223. BAD_POLYGON,
  224. BAD_LIGHTING,
  225. BAD_MATERIAL_IN_POLY,
  226. NOT_ENOUGH_VERTICES,
  227.  
  228. BAD_SUB_OBJECT,
  229. SUB_OBJECT_NOT_FOUND,
  230. BAD_LOD,
  231. BAD_TREE,
  232. BAD_OBJECT,
  233.  
  234. BAD_TEXTURE,
  235. BAD_VIEW
  236. };
  237.  
  238. char *mwErrorList[] = {
  239. "Unexpected end of file",
  240. "Not a model file",
  241. "Bad file",
  242. "File not found",
  243. "Tried to read/write too many reals",
  244.  
  245. "Bad string in file",
  246. "Unsupported file revision. You need a newer version of the modeller or file exporter...",
  247. "Bad material index",
  248. "Error in materials",
  249. "Bad vertex definition",
  250.  
  251. "Bad vertex index",
  252. "Bad polygon definition",
  253. "Unknown lighting in polygon",
  254. "Polygon has bad material",
  255. "Polygon has less than 3 vertices",
  256.  
  257. "Rubbish in sub object",
  258. "Undefined sub object in Lod",
  259. "Rubbish in LOD definition",
  260. "Bad tree definition",
  261. "Bad object definition",
  262.  
  263. "Bad texture definition",
  264. "Bad view definition"
  265. };
  266.  
  267. static void SetError(int type)
  268. {
  269.     FileError = TRUE;
  270.     FileErrorType = type;
  271. }
  272.  
  273. static void fail(char *function, char *message)
  274. {
  275.     fprintf(stderr, "%s:\n%s\n", function, message);
  276.     exit(666);
  277. }
  278. /************************************************************************
  279. Decide the byte sex of the machine
  280. ************************************************************************/
  281. static boolean BigEndian(void)
  282. {
  283.     int x = 1;
  284.     char *c = (char*)&x;
  285.     return (*c ISNT 1);
  286. }
  287. /************************************************************************
  288. See if a file is an image file
  289. ************************************************************************/
  290. #define IMAGIC 0732
  291. static boolean IsAnImageFile(char *name)
  292. {
  293.     reg FILE *f;
  294.     reg byte h0 = 0,  h1 = 0;
  295.  
  296.     if (f = fopen(name,"rb")) {
  297.     h0 = fgetc(f);
  298.     h1 = fgetc(f);
  299.     fclose(f);
  300.     return ( (((h0<<8)|h1) IS IMAGIC) OR (((h1<<8)|h0) IS IMAGIC) );
  301.     }
  302.     else {
  303.     return FALSE;
  304.     }
  305. }
  306. /************************************************************************
  307. Split a filename into path/name
  308. ************************************************************************/
  309. static void SplitFileName(reg char *s, reg char **path, reg char **name)
  310. {
  311.     char *search, *find;
  312.     static char workspace[MaxFileName], nullpath[] = "\0";
  313.  
  314.     search = workspace;
  315.     strcpy(workspace,s);
  316.     while (find = strchr(search,'/')) {
  317.     search = ++find;
  318.     }
  319.     if (search IS workspace) {    /* No path in name... */
  320.     *path = nullpath;
  321.     *name = search;
  322.     }
  323.     else {
  324.     *path = workspace;
  325.     *name = search--;
  326.     *search = '\0';        /* Split into path/name... */
  327.     }
  328. }
  329. /************************************************************************
  330. Search for a file....
  331. ************************************************************************/
  332. static boolean CheckFile(reg char *file, reg boolean (*check)(char*))
  333. {
  334.     reg int type;
  335.     struct stat statinfo;
  336.  
  337.     if (stat(file, &statinfo) ISNT -1) {
  338.     type = statinfo.st_mode & S_IFMT;
  339.     if (type IS S_IFREG) {
  340.         if (check) {
  341.         return check(file);
  342.         }
  343.         else {
  344.         return TRUE;
  345.         }
  346.     }
  347.     }
  348.     return FALSE;
  349. }
  350. static char *SearchForFile(reg char *searchpath, reg boolean (*check)(char*), reg char *name)
  351. {
  352.     reg flag found;
  353.     struct stat statinfo;
  354.     reg int i, nofiles, type;
  355.     char recurse[MaxFileName];
  356.     struct dirent **filelist, *this;
  357.  
  358.     static char result[MaxFileName];
  359.  
  360.  
  361.     nofiles = scandir(searchpath, &filelist, NULL, NULL);
  362.     if (nofiles > 0) {
  363.  
  364. /* Search the directory */
  365.     found = FALSE;
  366.     for (i=0; i<nofiles; i++) {
  367.         this = filelist[i];
  368.         this->d_ino = FALSE;
  369.         if (this->d_name[0] ISNT '.') {        /* Ignore system files */
  370.         sprintf(result, "%s/%s", searchpath, this->d_name);
  371.         if (!strcmp(this->d_name, name)) {
  372.             if (CheckFile(result, check)) {
  373.             found = TRUE;
  374.             break;
  375.             }
  376.         }
  377.         else if (stat(result, &statinfo) ISNT -1) {
  378.             type = statinfo.st_mode & S_IFMT;
  379.             this->d_ino = (type IS S_IFDIR);    /* flag the directories... */
  380.         }
  381.         }
  382.     }
  383.  
  384. /* If (!found), search any subdirectorys */
  385.     if (!found) {
  386.         for (i=0; i<nofiles; i++) {
  387.         this = filelist[i];
  388.         if (this->d_ino) {
  389.             sprintf(recurse, "%s/%s", searchpath, this->d_name);
  390.             if (SearchForFile(recurse, check, name)) {
  391.             found = TRUE;
  392.             break;
  393.             }
  394.         }
  395.         }
  396.     }
  397.  
  398. /* Free up storage created by scandir */
  399.     for (i=0; i<nofiles; i++) {
  400.         free(filelist[i]);
  401.     }
  402.     free(filelist);
  403.  
  404. /* Return file name if found */
  405.     if (found) {
  406.         return result;
  407.     }
  408.     }
  409.     return NULL;
  410. }
  411. static char *FindFile(reg char *startname, reg boolean (*check)(char*), reg char *startpath, reg char *subdirectory)
  412. {
  413.     reg char *nn;
  414.     reg flag done;
  415.     static char filename[MaxFileName];
  416.     char *path, *name, searchpath[MaxFileName];
  417.  
  418. /* Try relative filename. This is first because this is how we tell you to organise things... */
  419.     done = FALSE;
  420.     nn = startname;
  421.     while (!strncmp(nn, "./", 2)) {
  422.     nn += 2;
  423.     done = TRUE;
  424.     }
  425.     if (done) {
  426.     sprintf(filename, "%s/%s", startpath, nn);
  427.     if (CheckFile(filename, check)) {
  428.         return filename;
  429.     }
  430.     }
  431.  
  432. /* Try the absolute filename */
  433.     if (startname[0] IS '/') {
  434.     strcpy(filename, startname);
  435.     if (CheckFile(filename, check)) {
  436.         return filename;
  437.     }
  438.     }
  439.  
  440. /* Look in the directory where the model file is */
  441.     SplitFileName(startname, &path, &name);
  442.     sprintf(filename, "%s/%s", startpath, name);
  443.     if (CheckFile(filename, check)) {
  444.     return filename;
  445.     }
  446.     
  447. /* Look in the directory where it was last saved */
  448.     SplitFileName(startname, &path, &name);
  449.     sprintf(filename, "%s/%s", mwOriginalPath, name);
  450.     if (CheckFile(filename, check)) {
  451.     return filename;
  452.     }
  453.     
  454. /* Search the directory tree below the model file */
  455.     sprintf(searchpath, "%s/%s", startpath, subdirectory);
  456.     return SearchForFile(searchpath, check, name);
  457. }
  458. /************************************************************************
  459. Start creating a new model file
  460. ************************************************************************/
  461. ModelFilePtr NewModelFile(void)
  462. {
  463.     reg ModelFilePtr f;
  464.     CurrentModelFile = f = Allocate(sizeof(ModelFile));
  465.     f->FirstObject = NULL;
  466.     f->FirstTexture = NULL;
  467.     f->FirstMaterial = NULL;
  468.     return f;
  469. }
  470. /************************************************************************
  471. Storage routines - materials/textures
  472. ************************************************************************/
  473. static MaterialPtr NewMaterial(void)
  474. {
  475.     reg int i;
  476.     reg MaterialPtr new = Allocate(sizeof(Material));
  477.  
  478.     new->Next        = NULL;
  479.     new->Name        = NULL;
  480.     new->Used        = FALSE;
  481.     new->Name        = CopyOfString("Unnamed");
  482.  
  483.     for (i=0; i<3; i++) {        /* A grey material */
  484.     new->Ambient[i]     = 0.2;
  485.     new->Diffuse[i]     = 0.5;
  486.     new->Specular[i] = 1.0;
  487.     new->Emissive[i] = 0.0;
  488.     }
  489.     new->Shine = 64;
  490.     new->Alpha = 1.0;
  491.     new->pfdef = NULL;
  492.  
  493.     return new;
  494. }
  495. static void FreeMaterial(MaterialPtr m)
  496. {
  497.     if (m) {
  498.     if (m->Name) {
  499.         Free(m->Name);
  500.     }
  501.     Free(m);
  502.     }
  503. }
  504. static void AddMaterial(MaterialPtr m)
  505. {
  506.     reg MaterialPtr search;
  507.     if (search = CurrentModelFile->FirstMaterial) {
  508.     while (search->Next) {
  509.         search = search->Next;
  510.     }
  511.     search->Next = m;
  512.     }
  513.     else {
  514.     CurrentModelFile->FirstMaterial = m;
  515.     }
  516.     m->Next = NULL;
  517. }
  518. MaterialPtr mwAddMaterial(char *name)
  519. {
  520.     reg MaterialPtr new = NewMaterial();
  521.     new->Name = CopyOfString((name)? name: "Default");
  522.     AddMaterial(new);
  523.     return new;
  524. }
  525. static void RenameMaterial(MaterialPtr m, char *newname)
  526. {
  527.     if (m->Name) {
  528.     Free(m->Name);
  529.     }
  530.     if (newname) {
  531.     m->Name = CopyOfString(newname);
  532.     }
  533.     else {
  534.     m->Name = NULL;
  535.     }
  536. }
  537. static TexturePtr NewTexture(void)
  538. {
  539.     reg TexturePtr new = Allocate(sizeof(Texture));
  540.  
  541.     new->Next = NULL;
  542.     new->pfdef = NULL;
  543.  
  544.     new->MinFilter = MT_NULL;
  545.     new->MagFilter = MT_NULL;
  546.     new->ClampX = FALSE;
  547.     new->ClampY = FALSE;
  548.     new->Fast = FALSE;
  549.     new->Transparent = TRUE;
  550.     new->AlphaTest = 25;
  551.  
  552.     return new;
  553. }
  554. static void FreeTexture(TexturePtr t)
  555. {
  556.     if (t) {
  557.     if (t->File) {
  558.         Free(t->File);
  559.     }
  560.     Free(t);
  561.     }
  562. }
  563. static void AddTexture(reg TexturePtr t)
  564. {
  565.     reg TexturePtr search;
  566.  
  567.     if (search = CurrentModelFile->FirstTexture) {
  568.     while (search->Next) {
  569.         search = search->Next;
  570.     }
  571.     search->Next = t;
  572.     }
  573.     else {
  574.     CurrentModelFile->FirstTexture = t;
  575.     }
  576. }
  577. static void SearchForTextures(void)
  578. {
  579.     char *path, *name, newpath[MaxFileName];
  580.     reg TexturePtr t = CurrentModelFile->FirstTexture;
  581.  
  582.     while (t) {
  583.     if (ReadingExternal) {            /* Exrefs search in a different way */
  584.         path = ExternalObject->File;
  585.         if ((path[0] IS '.') AND (path[1] IS '/')) {
  586.         sprintf(newpath, "%s/%s", FilePath, path+2);
  587.         }
  588.         else {
  589.         strcpy(newpath, path);
  590.         }
  591.         SplitFileName(newpath, &path, &name);
  592.         strcpy(newpath, path);
  593.         path = newpath;
  594.     }
  595.     else {
  596.         path = FilePath;
  597.     }
  598.     if (name = FindFile(t->File, IsAnImageFile, path, "textures")) {
  599.         Free(t->File);
  600.         t->File = CopyOfString(name);
  601.     }
  602.     t = t->Next;
  603.     }
  604. }
  605. TexturePtr mwAddTexture(char *filename)
  606. {
  607.     TexturePtr new = NewTexture();
  608.     if (filename) {
  609.     new->File = CopyOfString(filename);
  610.     }
  611.     AddTexture(new);
  612.     return new;
  613. }
  614. /************************************************************************
  615. Storage routines - polygons
  616. ************************************************************************/
  617. PolygonBeadPtr NewPolygonBead(void)
  618. {
  619.     reg PolygonBeadPtr new = Allocate(sizeof(PolygonBead));
  620.  
  621.     new->Next = NULL;
  622.     new->Colour = DefaultColour;
  623.     new->Position[X] = new->Position[Y] = new->Position[Z] = 0.0;
  624.     new->TextureCoord[X] = new->TextureCoord[Y] = 0.0;
  625.     new->Normal[X] = new->Normal[Y] = new->Normal[Z] = 0.0;
  626.     new->Id = 0;
  627.     return new;
  628. }
  629. PolygonBeadPtr mwAddPolygonBead(PolygonBeadPtr *base, double *c, float *t)
  630. {
  631.     reg PolygonBeadPtr pb, new = NewPolygonBead();
  632.  
  633.     CopyXYZ(new->Position, c);
  634.     if (t) {
  635.     CopyXY(new->TextureCoord, t);
  636.     }
  637.     if (pb = *base) {
  638.     while (pb->Next) {
  639.         pb = pb->Next;
  640.     }
  641.     pb->Next = new;
  642.     }
  643.     else {
  644.     *base = new;
  645.     }
  646.     return new;
  647. }
  648. static PolygonBeadPtr AddPolygonBead(PolygonBeadPtr *base, real *c)
  649. {
  650.     return mwAddPolygonBead(base, c, NULL);
  651. }
  652. PolygonBeadPtr CopyOfPolygonBead(reg PolygonBeadPtr pb)
  653. {
  654.     reg PolygonBeadPtr new = Allocate(sizeof(PolygonBead));
  655.  
  656.     new->Next = NULL;
  657.     new->Colour = pb->Colour;
  658.     CopyXYZ(new->Normal, pb->Normal);
  659.     CopyXYZ(new->Position, pb->Position);
  660.     CopyXY(new->TextureCoord, pb->TextureCoord);
  661.     return new;
  662. }
  663. static PolygonPtr NewPolygon(void)
  664. {
  665.     reg PolygonPtr new = Allocate(sizeof(Polygon));
  666.  
  667.     new->Next        = NULL;
  668.     new->Child        = NULL;
  669.     new->Smooth        = TRUE;
  670.     new->Coloured    = TRUE;
  671.     new->Texture    = NULL;
  672.     new->Material    = NULL;
  673.     new->FirstBead    = NULL;
  674.     new->Envmapped    = FALSE;
  675.     new->LightGroup    = 0;
  676.     new->Normal[X]    =
  677.     new->Normal[Y]    =
  678.     new->Normal[Z]    = 0.0;
  679.     new->Colour        = DefaultColour;
  680.     return new;
  681. }
  682. static PolygonPtr PolygonCopier(reg PolygonPtr p)
  683. {
  684.     reg PolygonPtr new = NewPolygon();
  685.     reg PolygonBeadPtr pb, newpb, lastpb;
  686.  
  687.     new->Smooth        = p->Smooth;
  688.     new->Coloured    = p->Coloured;
  689.     new->Colour        = p->Colour;
  690.     new->Texture    = p->Texture;
  691.     new->Material    = p->Material;
  692.     new->Envmapped    = p->Envmapped;
  693.     new->LightGroup    = p->LightGroup;
  694.     CopyXYZ(new->Normal, p->Normal);
  695.     lastpb = NULL;
  696.     LoopThroughPolygonsBeads(p, pb) {
  697.     newpb = CopyOfPolygonBead(pb);
  698.     if (lastpb) {
  699.         lastpb->Next = newpb;
  700.     }
  701.     else {
  702.         new->FirstBead = newpb;
  703.     }
  704.     lastpb = newpb;
  705.     }
  706.     return new;
  707. }
  708. static void CopyChildren(reg PolygonPtr parent, reg PolygonPtr child)
  709. {
  710.     reg PolygonPtr new, lastc = NULL;
  711.     while (child) {
  712.     new = PolygonCopier(child);
  713.     if (lastc) {
  714.         lastc->Next = new;
  715.     }
  716.     else {
  717.         parent->Child = new;
  718.     }
  719.     lastc = new;
  720.     if (child->Child) {
  721.         CopyChildren(new, child->Child);
  722.     }
  723.     child = child->Next;
  724.     }
  725. }
  726. PolygonPtr CopyOfPolygon(reg PolygonPtr p)
  727. {
  728.     reg PolygonPtr new = PolygonCopier(p);
  729.     if (p->Child) {
  730.     CopyChildren(new, p->Child);
  731.     }
  732.     return new;
  733. }
  734. static void LinkPolygon(PolygonPtr p, TreePtr t, PolygonPtr parent)
  735. {
  736.     if (parent) {
  737.     p->Next = parent->Child;
  738.     parent->Child = p;
  739.     }
  740.     else if (t) {
  741.     p->Next = t->FirstPolygon;
  742.     t->FirstPolygon = p;
  743.     }
  744.     else {
  745.     fail("AddPolygon", "You must specify either a tree branch or a parent");
  746.     }
  747. }
  748. PolygonPtr AddPolygon(PolygonBeadPtr beads, TreePtr t, PolygonPtr parent)
  749. {
  750.     reg PolygonBeadPtr b = beads;
  751.     reg PolygonPtr new = NewPolygon();
  752.     new->FirstBead = b;
  753.     while (b) {
  754.     b->Owner = new;
  755.     b = b->Next;
  756.     }
  757.     LinkPolygon(new, t, parent);
  758.     return new;
  759. }
  760. static void TrashPolygon(reg PolygonPtr p)
  761. {
  762.     reg PolygonBeadPtr pb, nextpb;
  763.     pb = p->FirstBead;
  764.     while (pb) {
  765.     nextpb = pb->Next;
  766.     Free(pb);
  767.     pb = nextpb;
  768.     }
  769.     Free(p);
  770. }
  771. static void ChildFreer(reg PolygonPtr p)
  772. {
  773.     reg PolygonPtr child, nextp;
  774.     while (p) {
  775.     nextp = p->Next;
  776.     if (child = p->Child) {
  777.         ChildFreer(child);
  778.     }
  779.     TrashPolygon(p);
  780.     p = nextp;
  781.     }
  782. }
  783. void FreePolygon(PolygonPtr p)
  784. {
  785.     reg PolygonPtr child;
  786.     reg PolygonBeadPtr pb, nextpb;
  787.  
  788.     if (child = p->Child) {
  789.     ChildFreer(child);
  790.     }
  791.     pb = p->FirstBead;
  792.     while (pb) {
  793.     nextpb = pb->Next;
  794.     Free(pb);
  795.     pb = nextpb;
  796.     }
  797.     Free(p);
  798. }
  799. /************************************************************************
  800. Storage routines - tree branches
  801. ************************************************************************/
  802. static void Identify(real (*mat)[4])
  803. {
  804.     reg real zero = 0.0, one = 1.0;
  805.     mat[X][X] = one;  mat[X][Y] = zero;  mat[X][Z] = zero;  mat[X][W] = zero;
  806.     mat[Y][X] = zero; mat[Y][Y] = one;   mat[Y][Z] = zero;  mat[Y][W] = zero;
  807.     mat[Z][X] = zero; mat[Z][Y] = zero;  mat[Z][Z] = one;   mat[Z][W] = zero;
  808.     mat[W][X] = zero; mat[W][Y] = zero;  mat[W][Z] = zero;  mat[W][W] = one;
  809. }
  810. TreePtr NewTreeBranch(int type, char *name)
  811. {
  812.     TreePtr new = Allocate(sizeof(Tree));
  813.  
  814.     bzero(new, sizeof(Tree));
  815.     if (name) {
  816.     reg int i, l;
  817.     char newname[MaxName];
  818.     strncpy(newname, name, MaxName);
  819.     name = newname;
  820.     l = strlen(name);
  821.     if (l > (MaxName-1)) {
  822.         l = MaxName-1;
  823.     }
  824.     for (i=0; i<l; i++) {
  825.         if ((name[i] < 32) OR (name[i] > 126)) {
  826.         name[i] = '.';
  827.         }
  828.     }
  829.     name[i] = '\0';
  830.     }
  831.     else {
  832.     switch (type) {
  833.         case GroupBranch:        name = "Group";        break;
  834.         case PolygonBranch:        name = "Poly";        break;
  835.         case LodBranch:        name = "Lod";        break;
  836.         case InstanceBranch:    name = "Object";    break;
  837.         case SwitchBranch:        name = "Switch";    break;
  838.         case SwitchOutput:        name = "Switch";    break;
  839.         case DcsBranch:
  840.         case DcsOutput:        name = "DCS";        break;
  841.         case VRMLBranch:        name = "VRML";        break;
  842.  
  843.         case ActivatorEngine:    name = "Activator";    break;
  844.         case DeactivatorEngine:    name = "Deactivator";    break;
  845.  
  846.         case TimeEngine:        name = "Time";        break;
  847.         case LineEngine:        name = "Line";        break;
  848.         case AngleEngine:        name = "Angle";        break;
  849.         case WaveEngine:        name = "Wave";        break;
  850.         case SensorEngine:        name = "Sensor";    break;
  851.  
  852.         case ScalarEngine:        name = "Scalar";    break;
  853.         case SplineEngine:        name = "Spline";    break;
  854.         case CompareEngine:        name = "Compare";    break;
  855.         case MatrixEngine:        name = "Matrix";    break;
  856.  
  857.         default:            fail("NewTreeBranch", "Unknown branch type");
  858.     }
  859.     }
  860.     new->Type        = type;
  861.     new->Name        = CopyOfString(name);
  862.     new->HasEye        = TRUE;
  863.     new->EyeOpen    = TRUE;
  864.     new->Visible    = TRUE;
  865.  
  866.     new->Backfaced    = TRUE;
  867.     new->ShareNormals    = TRUE;
  868.  
  869.     new->SwitchOut    = 10000;
  870.     new->IsInline    = TRUE;
  871.  
  872.     new->SeqTime    = 0.0;
  873.     new->SeqType    = mwSeqCycle;
  874.     
  875.     Identify(new->Transformation);
  876.     Identify(new->DcsMatrix);
  877.  
  878.     new->StartActive        = TRUE;
  879.     new->NoWaves        = 1.0;
  880.     new->WaveTime        = 1.0;
  881.     new->Scale            = 1.0;
  882.  
  883.     return new;
  884. }
  885. static void RenameBranch(TreePtr t, char *newname)
  886. {
  887.     if (t->Name) {
  888.     Free(t->Name);
  889.     }
  890.     if (newname) {
  891.     t->Name = CopyOfString(newname);
  892.     }
  893.     else {
  894.     t->Name = NULL;
  895.     }
  896. }
  897. void FreeTree(TreePtr t)
  898. {
  899.     reg PolygonPtr p, nextp;
  900.     reg TreePtr recurse, next;
  901.     while (t) {
  902.     next = t->Down;
  903.     if (recurse = t->Across) {
  904.         FreeTree(recurse);
  905.     }
  906.     if (t->Type IS PolygonBranch) {
  907.         p = t->FirstPolygon;
  908.         while (p) {
  909.         nextp = p->Next;
  910.         FreePolygon(p);
  911.         p = nextp;
  912.         }
  913.     }
  914.     if (t->Name) {
  915.         Free(t->Name);
  916.     }
  917.     Free(t);
  918.     t = next;
  919.     }
  920. }
  921. static void TreeScanner(TreePtr t, void (*callback)(reg const TreePtr, reg const void*), void *vars)
  922. {
  923.     while (t) {
  924.     callback(t, vars);
  925.     if (t->Across) {
  926.         TreeScanner(t->Across, callback, vars);
  927.     }
  928.     t = t->Down;
  929.     }
  930. }
  931. void ScanTree(reg TreePtr t, void (*callback)(reg const TreePtr, reg const void*), void *vars)
  932. {
  933.     if (t) {
  934.     callback(t, vars);
  935.     TreeScanner(t->Across, callback, vars);
  936.     }
  937. }
  938. void mwAddTreeBranch(TreePtr parent, TreePtr newchild)
  939. {
  940.     reg TreePtr t = parent;
  941.     if (t->Across) {
  942.     t = t->Across;
  943.     while (t->Down) {
  944.         t = t->Down;
  945.     }
  946.     t->Down = newchild;
  947.     }
  948.     else {
  949.     t->Across = newchild;
  950.     }
  951.     newchild->Down = NULL;
  952. }
  953. /************************************************************************
  954. Storage routines - motion paths
  955. ************************************************************************/
  956. PathPtr NewPath(void)
  957. {
  958.     reg PathPtr p = Allocate(sizeof(Path));
  959.  
  960.     p->FirstBead = NULL;
  961.     p->Closed = FALSE;
  962.     p->Smoothing = 2;
  963.     p->Basis = BSpline;
  964.  
  965.     return p;
  966. }
  967. PathBeadPtr AddBeadToPathEnd(reg PathPtr p, reg CoordinatePtr c)
  968. {
  969.     reg PathBeadPtr b = p->FirstBead, new = Allocate(sizeof(PathBead));
  970.     new->Rounded    = TRUE;
  971.  
  972.     if (b) {
  973.     while (b->Next) {
  974.         b = b->Next;
  975.     }
  976.     b->Next = new;
  977.     }
  978.     else {
  979.     p->FirstBead = new;
  980.     }
  981.  
  982.     return new;
  983. }
  984. /************************************************************************
  985. Storage routines - objects
  986. ************************************************************************/
  987. ModelObjectPtr AddObject(char *name)
  988. {
  989.     reg ModelObjectPtr search, new = Allocate(sizeof(ModelObject));
  990.  
  991.     if (search = CurrentModelFile->FirstObject) {
  992.     while (search->Next) {
  993.         search = search->Next;
  994.     }
  995.     search->Next = new;
  996.     }
  997.     else {
  998.     CurrentModelFile->FirstObject = new;
  999.     }
  1000.     new->Next = NULL;
  1001.  
  1002.     if (!name) {
  1003.     name = "Unnamed";
  1004.     }
  1005.     new->Name                = CopyOfString(name);
  1006.     new->Tree                = NULL;
  1007.     new->Engines            = NULL;
  1008.     new->IsTopLevel            = FALSE;
  1009.     new->FirstConstructionVertex    = NULL;
  1010.     new->File                = NULL;
  1011.     new->External            = NULL;
  1012.     return new;
  1013. }
  1014. static void FreeObject(reg ModelObjectPtr o)
  1015. {
  1016.     if (o->External) {
  1017.     o->Tree = NULL;
  1018.     FreeExternalFile(o->External);
  1019.     }
  1020.     FreeTree(o->Tree);
  1021.     if (o->Name) {
  1022.     Free(o->Name);
  1023.     }
  1024.     Free(o);
  1025. }
  1026. /************************************************************************
  1027. Initialisation/finalisation of file read...
  1028. ************************************************************************/
  1029. static FILE *GetReadyForRead(char *name)
  1030. {
  1031.     FILE *f;
  1032.     if (f = fopen(name, "rb")) {
  1033.     FileError = FALSE;
  1034.     NewModelFile();
  1035.     mwOriginalPath[0] = '\0';
  1036.     }
  1037.     else {
  1038.     SetError(FILE_NOT_FOUND);
  1039.     }
  1040.     return f;
  1041. }
  1042. static void FinishReading(FILE *f, float compatibility)
  1043. {
  1044.     if (f) {
  1045.     fclose(f);
  1046.     }
  1047. }
  1048. /************************************************************************
  1049. Free the storage used by a model file
  1050. ************************************************************************/
  1051. static void FreeExternalFile(reg ModelFilePtr f)
  1052. {
  1053.     reg TexturePtr t, nextt;
  1054.     reg MaterialPtr m, nextm;
  1055.     reg ModelObjectPtr o, nexto;
  1056.  
  1057.     o = f->FirstObject;
  1058.     while (o) {
  1059.     nexto = o->Next;
  1060.     FreeObject(o);
  1061.     o = nexto;
  1062.     }
  1063.     t = f->FirstTexture;
  1064.     while (t) {
  1065.     nextt = t->Next;
  1066.     FreeTexture(t);
  1067.     t = nextt;
  1068.     }
  1069.     m = f->FirstMaterial;
  1070.     while (m) {
  1071.     nextm = m->Next;
  1072.     FreeMaterial(m);
  1073.     m = nextm;
  1074.     }
  1075.     Free(f);
  1076. }
  1077. void mwFreeFile(ModelFilePtr f)
  1078. {
  1079.     reg TexturePtr t, nextt;
  1080.     reg MaterialPtr m, nextm;
  1081.     reg ModelObjectPtr o, nexto;
  1082.     o = f->FirstObject;
  1083.     while (o) {
  1084.     nexto = o->Next;
  1085.     FreeObject(o);
  1086.     o = nexto;
  1087.     }
  1088.     t = f->FirstTexture;
  1089.     while (t) {
  1090.     nextt = t->Next;
  1091.     FreeTexture(t);
  1092.     t = nextt;
  1093.     }
  1094.     m = f->FirstMaterial;
  1095.     while (m) {
  1096.     nextm = m->Next;
  1097.     FreeMaterial(m);
  1098.     m = nextm;
  1099.     }
  1100.     Free(f);
  1101. }
  1102. /************************************************************************
  1103. Convert between coordinate systems
  1104. ************************************************************************/
  1105. static int ConvertDirection;
  1106. enum { To_Y_is_up, To_Z_is_up };
  1107. #define ConvertXYZ(c, temp)        \
  1108. if (ConvertDirection IS To_Y_is_up) {    \
  1109.     temp = c[Y];            \
  1110.     c[Y] = c[Z];            \
  1111.     c[Z] = -temp;            \
  1112. }                    \
  1113. else {                    \
  1114.     temp = c[Y];            \
  1115.     c[Y] = -c[Z];            \
  1116.     c[Z] = temp;            \
  1117. }
  1118. #define ConvertPoly            \
  1119. LoopThroughPolygonsBeads(p, pb) {    \
  1120.     ConvertXYZ(pb->Position, dtemp);    \
  1121. }                    \
  1122. ConvertXYZ(p->Normal, temp);        \
  1123. if (p->Smooth AND !p->Coloured) {    \
  1124.     LoopThroughPolygonsBeads(p, pb) {    \
  1125.     ConvertXYZ(pb->Normal, temp);    \
  1126.     }                    \
  1127. }
  1128.  
  1129. static void ConvertChildren(reg PolygonPtr p)
  1130. {
  1131.     reg float temp;
  1132.     reg double dtemp;
  1133.     reg PolygonBeadPtr pb;
  1134.  
  1135.     while (p) {
  1136.     ConvertPoly;
  1137.     if (p->Child) {
  1138.         ConvertChildren(p->Child);
  1139.     }
  1140.     p = p->Next;
  1141.     }
  1142. }
  1143. static void ConvertTree(reg TreePtr t)
  1144. {
  1145.     reg int i;
  1146.     reg float temp;
  1147.     reg double dtemp;
  1148.     reg PolygonPtr p;
  1149.     reg PolygonBeadPtr pb;
  1150.     while (t) {
  1151.     if (t->Across) {
  1152.         ConvertTree(t->Across);
  1153.     }
  1154.     if (t->Type IS PolygonBranch) {
  1155.         LoopThroughBranchesPolygons(t, p) {
  1156.         ConvertPoly;
  1157.         if (p->Child) {
  1158.             ConvertChildren(p->Child);
  1159.         }
  1160.         }
  1161.     }
  1162.     else if (t->Type IS InstanceBranch) {
  1163.         for (i=0; i<4; i++) {
  1164.         if (ConvertDirection IS To_Y_is_up) {
  1165.             dtemp = t->Transformation[Y][i];
  1166.             t->Transformation[Y][i] = t->Transformation[Z][i];
  1167.             t->Transformation[Z][i] = -dtemp;
  1168.         }
  1169.         else {
  1170.             dtemp = t->Transformation[Y][i];
  1171.             t->Transformation[Y][i] = -t->Transformation[Z][i];
  1172.             t->Transformation[Z][i] = dtemp;
  1173.         }
  1174.         }
  1175.         for (i=0; i<4; i++) {
  1176.         if (ConvertDirection IS To_Y_is_up) {
  1177.             dtemp = t->Transformation[i][Y];
  1178.             t->Transformation[i][Y] = t->Transformation[i][Z];
  1179.             t->Transformation[i][Z] = -dtemp;
  1180.         }
  1181.         else {
  1182.             dtemp = t->Transformation[i][Y];
  1183.             t->Transformation[i][Y] = t->Transformation[i][Z];
  1184.             t->Transformation[i][Z] = -dtemp;
  1185.         }
  1186.         }
  1187.     }
  1188.     t = t->Down;
  1189.     }
  1190. }
  1191. static void DoCoordinateConversion(void)
  1192. {
  1193.     reg ModelObjectPtr o = CurrentModelFile->FirstObject;
  1194.     while (o) {
  1195.     ConvertTree(o->Tree);
  1196.     o = o->Next;
  1197.     }
  1198. }
  1199. void mwConvertTo_Y_is_up(void)
  1200. {
  1201.     ConvertDirection = To_Y_is_up;
  1202.     DoCoordinateConversion();
  1203. }
  1204. void mwConvertTo_Z_is_up(void)
  1205. {
  1206.     ConvertDirection = To_Z_is_up;
  1207.     DoCoordinateConversion();
  1208. }
  1209. /************************************************************************
  1210. Read an external file...
  1211. ************************************************************************/
  1212. static ModelFilePtr LoadExternalFile(reg char *name)
  1213. {
  1214.     reg flag WasExternal;
  1215.     reg ModelFilePtr f, c;
  1216.     
  1217.     c = CurrentModelFile;
  1218.     WasExternal = ReadingExternal;
  1219.     ReadingExternal = TRUE;
  1220.     ReadModel(name);
  1221.     f = CurrentModelFile;
  1222.     if (FileError) {
  1223.     FreeExternalFile(f);
  1224.     f = NULL;
  1225.     }
  1226.     CurrentModelFile = c;
  1227.     ReadingExternal = WasExternal;
  1228.     return f;
  1229. }
  1230.